﻿using System;
using System.Linq;
using System.Reflection;
using System.IO;
using System.Net;
using Lextm.SharpSnmpLib.Messaging;

namespace ServerLib.Entities
{
    static class CurDir
    {
        static CurDir()
        {
            Get = Directory.GetCurrentDirectory();
        }

        public static string Get { get; private set; }
    }

    public class DllUnmanagedWork
    {
        private const string LibsPath = "\\Resources\\Libs\\";
        private readonly string _dllPath;
        private readonly string _dllName;
        private readonly string _deviceName;
        //private MethodInfo _callMethod;
        //private object _callClass;
        private bool _initialized;
        private DynamicFunc _dynamicFunc;

        public string DeviceName 
        {
            get { return _deviceName; }
        }

        /// <summary>
        /// Конструктор объекта для работы с устройствами.
        /// </summary>
        /// <param name="libName">Имя библиотеки.</param>
        /// <param name="devName">Имя устройства.</param>
        public DllUnmanagedWork(string libName, string devName)
        {
            _dllPath = CurDir.Get + LibsPath + libName;
            _dllName = libName;
            _deviceName = devName;
            _initialized = false;
        }

        public string GetStatus(string ip)
        {
            if (!_initialized)
            {
                var check = Initialize();
                if (check != "ok")
                {
                    return check;// "err:" + Server.Rm.GetString("DllNotInitialized") + ".\r\n" + _dllName;
                }
            }

            string[] parsString = { ip };
            var args = new object[2];
            args[0] = "getstatus";
            args[1] = parsString;
            return _dynamicFunc(args);
        }

        public string GetParams(string ip)
        {
            if (!_initialized)
            {
                var check = Initialize();
                if (check != "ok")
                {
                    return check;// "err:" + Server.Rm.GetString("DllNotInitialized") + ".\r\n" + _dllName;
                }
            }
               
            string[] parsString = { ip };
            var args = new object[2];
            args[0] = "getparams";
            args[1] = parsString;
            return _dynamicFunc(args);
        }

        /// <summary>
        /// Установка значений эталона и нормы измерителя.
        /// </summary>
        /// <param name="ip">IP-адрес устройства.</param>
        /// <param name="data">Новые параметры: 7 цифр - эталон, 2 цифры - норма.</param>
        /// <returns></returns>
        public string SetParams(string ip, string data)
        {
            if (!_initialized)
            {
                var check = Initialize();
                if (check != "ok")
                {
                    return check;// "err:" + Server.Rm.GetString("DllNotInitialized") + ".\r\n" + _dllName;
                }
            }
            string[] parsString = { ip, data };
            var args = new object[2];
            args[0] = "setparams";
            args[1] = parsString;
            return _dynamicFunc(args);
        }

        /// <summary>
        /// Обработка ловушки пришедшей по snmp (trap).
        /// Работает только с библиотекой SharpSnmpLib!!!
        /// </summary>
        /// <param name="devName">Имя устройства.</param>
        /// <param name="trap">Пришедшая ловушка (trap).</param>
        /// <param name="dt">Время события.</param>
        /// <returns></returns>
        public string TrapHandle(string devName, TrapV2Message trap, DateTime dt)
        {
            if (!_initialized)
            {
                var check = Initialize();
                if (check != "ok")
                {
                    return check;// "err:" + Server.Rm.GetString("DllNotInitialized") + ".\r\n" + _dllName;
                }
            }
            object[] parsString = { devName, trap, dt };
            var args = new object[2];
            args[0] = "traphandle";
            args[1] = parsString;
            return _dynamicFunc(args);
        }

        /// <summary>
        /// Получение журнала измерителя и сохранение в папку resources\logs.
        /// </summary>
        /// <param name="ip">IP-адрес устройства.</param>
        /// <param name="path">Путь для сохранения файла журнала.</param>
        /// <returns></returns>
        public string GetLog(string ip, string path)
        {
            if (!_initialized)
            {
                var check = Initialize();
                if (check != "ok")
                {
                    return check;// "err:" + Server.Rm.GetString("DllNotInitialized") + ".\r\n" + _dllName;
                }
            }
            string[] parsString = { ip, path };
            var args = new object[2];
            args[0] = "getlog";
            args[1] = parsString;
            try
            {
                return _dynamicFunc(args);
            }
            catch (Exception ex)
            {
                if (ex is TargetInvocationException && ex.InnerException != null)
                    return "err:" + ex.InnerException.Message + ": " + ip;
                return "err:" + ex.Message + ": " + ip;
            }
            //return t_vips_analizator.T_VIPS.CallMethod((string)args[0], (string[])args[1]);
        }

        public string Flush()
        {
            if (!_initialized)
            {
                var check = Initialize();
                if (check != "ok")
                {
                    return check;
                }
            }
            var args = new object[2];
            args[0] = "flush";
            args[1] = null;
            try
            {
                return _dynamicFunc(args);
            }
            catch (Exception ex)
            {
                return "err:" + ex.Message;
            }
        }
        
        public string Initialize()
        {
            if (!File.Exists(_dllPath))
            {
                if(string.IsNullOrEmpty(_dllName))
                    return "err:" + Server.Rm.GetString("DllIsNotExist");
                return "err:" + Server.Rm.GetString("DllIsNotExist") + ": " + _dllName;
            }
            try
            {
                Assembly assemblyDll = Assembly.LoadFile(_dllPath);
                Type[] typeslist = assemblyDll.GetExportedTypes();
                MethodInfo[] methods = typeslist[0].GetMethods();
                var callMethod = methods.First(met => met.Name.Contains("CallMethod"));
                var callClass = Activator.CreateInstance(typeslist[0]);
                _dynamicFunc = MakeDynamicFunc(callClass, callMethod);
            }
            catch (Exception ex)
            {
                return "err:" + ex.Message + "\r\n" + _dllName;
            }
            _initialized = true;
            return "ok";
        }

        private delegate string DynamicFunc(params object[] parameters);

        private static DynamicFunc MakeDynamicFunc(object target, MethodInfo method)
        {
            return par => (string) method.Invoke(target, par);
        }

    }
}
